package de.hdu.mfz.ctrl;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import de.hdu.mfz.dao.RouteDAO;
import de.hdu.mfz.dao.UserDAO;
import de.hdu.mfz.dto.AJAXMessage;
import de.hdu.mfz.dto.RouteZeile;
import de.hdu.mfz.dto.RouteZeile_Ort;
import de.hdu.mfz.model.Route;
import de.hdu.mfz.model.Routenpunkt;
import de.hdu.mfz.model.User;

@Controller
public class MarkusTestController {

	//ArrayList<RouteZeile> dummyZeilen = new ArrayList<RouteZeile>();
	ArrayList<Route> dummyRouten = new ArrayList<Route>();
	
	public MarkusTestController() {
		/*int i=0;
		RouteZeile dummy;
		dummy = new RouteZeile(3);
		dummy.fahrer = "Markus";
		dummy.zeit = "heute";
		dummy.id = ++i;
		dummy.platz = "3/5";
		dummy.orte_kurz[0].name = "Ort1";
		dummy.orte_kurz[1].name = "Ort2";
		dummy.orte_kurz[2].name = "Ort3";
		dummyZeilen.add(dummy);
		
		dummy = new RouteZeile(3);
		dummy.fahrer = "ChefKoch";
		dummy.zeit = "heute";
		dummy.id = ++i;
		dummy.platz = "2/4";
		dummy.orte_kurz[0].name = "Passau";
		dummy.orte_kurz[1].name = "Deggendorf";
		dummy.orte_kurz[2].name = "Regensburg";
		dummyZeilen.add(dummy);
		
		dummy = new RouteZeile(4);
		dummy.fahrer = "Frl. Schmitt";
		dummy.zeit = "morgen";
		dummy.id = ++i;
		dummy.platz = "2/4";
		dummy.orte_kurz[0].name = "München";
		dummy.orte_kurz[1].name = "...";
		dummy.orte_kurz[2].name = "Deggendorf";
		dummy.orte_kurz[3].name = "Regensburg";
		dummyZeilen.add(dummy);
		
		dummy = new RouteZeile(2);
		dummy.fahrer = "Frl. Schmitt";
		dummy.zeit = "morgen";
		dummy.id = ++i;
		dummy.platz = "2/4";
		dummy.orte_kurz[0].name = "München";
		dummy.orte_kurz[1].name = "Deggendorf";
		dummyZeilen.add(dummy);

		dummy = new RouteZeile(4);
		dummy.fahrer = "Katharina";
		dummy.zeit = "gestern";
		dummy.id = ++i;
		dummy.platz = "4/5";
		dummy.orte_kurz[0].name = "Waldkirchen";
		dummy.orte_kurz[1].name = "...";
		dummy.orte_kurz[2].name = "Iggensbach";
		dummy.orte_kurz[3].name = "Deggendorf";
		dummyZeilen.add(dummy);

		dummy = new RouteZeile(5);
		dummy.fahrer = "Katharina";
		dummy.zeit = "heute";
		dummy.id = ++i;
		dummy.platz = "1/5";
		dummy.orte_kurz[0].name = "Waldkirchen";
		dummy.orte_kurz[1].name = "...";
		dummy.orte_kurz[2].name = "Iggensbach";
		dummy.orte_kurz[3].name = "...";
		dummy.orte_kurz[4].name = "Deggendorf";
		dummyZeilen.add(dummy);*/
		
		/*try {
			SimpleDateFormat sdf = new SimpleDateFormat("dd.mm.yyyy");
			Route dr;
			LinkedHashSet<Routenpunkt> lst;
			*/
			dr = new Route();
			dr.setFahrer("Markus");
			dr.setPlaetze(1); 
			dr.setRouteId(0); 
			dr.setStartzeit(sdf.parse("01.01.2012"));
			dr.setZielzeit(sdf.parse("01.01.2012"));
			lst = new LinkedHashSet<Routenpunkt>();
			lst.add(new Routenpunkt("Passau"));
			lst.add(new Routenpunkt("Deggendorf"));
			lst.add(new Routenpunkt("Regensburg"));
			lst.add(new Routenpunkt("Nürnberg"));
			dr.setListe(lst);
			dummyRouten.add(dr);
			
			dr = new Route();
			dr.setFahrer("Markus");
			dr.setPlaetze(1); 
			dr.setRouteId(1); 
			dr.setStartzeit(sdf.parse("01.01.2012"));
			dr.setZielzeit(sdf.parse("01.01.2012"));
			lst = new LinkedHashSet<Routenpunkt>();
			lst.add(new Routenpunkt("Passau"));
			lst.add(new Routenpunkt("Iggensbach"));
			lst.add(new Routenpunkt("Deggendorf"));
			dr.setListe(lst);
			dummyRouten.add(dr);
			
			dr = new Route();
			dr.setFahrer("Markus");
			dr.setPlaetze(1); 
			dr.setRouteId(2); 
			dr.setStartzeit(sdf.parse("01.01.2012"));
			dr.setZielzeit(sdf.parse("01.01.2012"));
			lst = new LinkedHashSet<Routenpunkt>();
			lst.add(new Routenpunkt("Wien"));
			lst.add(new Routenpunkt("Linz"));
			lst.add(new Routenpunkt("Passau"));
			lst.add(new Routenpunkt("Aicha"));
			lst.add(new Routenpunkt("Iggensbach"));
			lst.add(new Routenpunkt("Hengersberg"));
			lst.add(new Routenpunkt("Deggendorf"));
			dr.setListe(lst);
			dummyRouten.add(dr);			
			
			dr = new Route();
			dr.setFahrer("Markus");
			dr.setPlaetze(1); 
			dr.setRouteId(3); 
			dr.setStartzeit(sdf.parse("01.01.2012"));
			dr.setZielzeit(sdf.parse("01.01.2012"));
			lst = new LinkedHashSet<Routenpunkt>();
			lst.add(new Routenpunkt("Wien"));
			lst.add(new Routenpunkt("Linz"));
			lst.add(new Routenpunkt("Passau"));
			lst.add(new Routenpunkt("Aicha"));
			lst.add(new Routenpunkt("Iggensbach"));
			lst.add(new Routenpunkt("Hengersberg"));
			lst.add(new Routenpunkt("Deggendorf"));
			lst.add(new Routenpunkt("Regensburg"));
			dr.setListe(lst);
			dummyRouten.add(dr);
			
			dr = new Route();
			dr.setFahrer("Markus");
			dr.setPlaetze(1); 
			dr.setRouteId(4); 
			dr.setStartzeit(sdf.parse("01.01.2012"));
			dr.setZielzeit(sdf.parse("01.01.2012"));
			lst = new LinkedHashSet<Routenpunkt>();
			lst.add(new Routenpunkt("Passau"));
			lst.add(new Routenpunkt("Deggendorf"));
			dr.setListe(lst);
			dummyRouten.add(dr);
			
			dr = new Route();
			dr.setFahrer("Markus");
			dr.setPlaetze(1); 
			dr.setRouteId(5); 
			dr.setStartzeit(sdf.parse("01.01.2012"));
			dr.setZielzeit(sdf.parse("01.01.2012"));
			lst = new LinkedHashSet<Routenpunkt>();
			lst.add(new Routenpunkt("Passau"));
			lst.add(new Routenpunkt("Deggendorf"));
			lst.add(new Routenpunkt("Regensburg"));
			lst.add(new Routenpunkt("Deggendorf"));
			lst.add(new Routenpunkt("Passau"));
			dr.setListe(lst);
			dummyRouten.add(dr);
			
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}*/
	}
		
	@RequestMapping(value="/sucheRoute.json", method=RequestMethod.GET)
	public @ResponseBody AJAXMessage searchRoute(String von, String nach, String tag, HttpSession session) {
		Date abfahrt;
		GregorianCalendar cal = new GregorianCalendar();
		
		if (von == "") {
			// TODO: Ggf. Fehlermeldungen übersetzten in mehrere Sprachen
			return new AJAXMessage(false, AJAXMessage.FailureCode.WarningMessage, "Bitte geben Sie Ihren Abfahrtsort an.");	
		}
		if (nach == "") {
			return new AJAXMessage(false, AJAXMessage.FailureCode.WarningMessage, "Bitte geben Sie Ihren Zielort an.");	
		}
		if (tag == "") {
			return new AJAXMessage(false, AJAXMessage.FailureCode.WarningMessage, "Bitte gegen Sie ein Abfahrtsdatum an.");	
		}
		
		try {
			abfahrt = this.checkAndConvertDate(tag,null);
		} catch (Exception e) {
			return new AJAXMessage(false, AJAXMessage.FailureCode.WarningMessage, "Bitte geben Sie ein korrektes Datum ein! (tt.mm.jjjj)");
		}

		//ArrayList für Ergebnis. ArrayList hat den Vorteil, dass nach FIFO sortiert wird.
		ArrayList<RouteZeile> retListe = new ArrayList<RouteZeile>();
		RouteDAO dao = new RouteDAO();
		Set<Route> routen = dao.findRoute(von, nach);
		
		//Für jede Route ein RouteZeile-Objekt erzeugen und in Ergebnis-Array speichern.
		for (Route r : routen)
			retListe.add(new RouteZeile(r, von, nach));
		
	    return new AJAXMessage(true, AJAXMessage.FailureCode.None, retListe.toArray());
	}

	// TODO: Doku
	@RequestMapping(value="/getRoute.json", method=RequestMethod.GET)
	public @ResponseBody AJAXMessage getRoute(int id, HttpSession session) {

		for (Route r : dummyRouten)	{
			if (r.getRouteId() == id)
				return new AJAXMessage(true, AJAXMessage.FailureCode.None, new RouteZeile(r, "", "")); 
		}
		return new AJAXMessage(false, AJAXMessage.FailureCode.WarningMessage, "Fahrt wurde leider zwischenzeitlich gelöscht.");
	}
	
	// TODO: Doku
	@RequestMapping(value="/joinRoute.json", method=RequestMethod.GET)
	public @ResponseBody AJAXMessage joinRoute(int id, HttpSession session) {

		//Für diese Funktion ist ein Login erforderlich
		User myUser;
		try {
			myUser = this.getUserFromSession(session);
		} catch (Exception e) {
			return new AJAXMessage(false, AJAXMessage.FailureCode.LoginRequired, e.getMessage());
		}
		
		// TODO Sinnvoller Code. Jetzt nur Zufallsgenerator zum Testen
		Random randomGenerator = new Random();
		switch (randomGenerator.nextInt(3)) {
			case 0:
				return new AJAXMessage(false, AJAXMessage.FailureCode.InfoMessage, "Gratulation. Sie sind Mitfahrer.");
			case 1:
				return new AJAXMessage(false, AJAXMessage.FailureCode.WarningMessage, "Route wurde entweder zwischenzeitlich gelöscht oder ist voll.");
			default: 
				return new AJAXMessage(false, AJAXMessage.FailureCode.ErrorMessage, "Schwerwiegender Fehler.");
		}
		
		
	}
	
	// TODO: Doku
	@SuppressWarnings("unchecked")
	@RequestMapping(value="/saveRoute.json", method=RequestMethod.POST)
	public @ResponseBody AJAXMessage saveRoute(@RequestParam Map<String, String> params, HttpSession session) {

		//Für diese Funktion ist ein Login erforderlich
		User myUser;
		try {
			myUser = this.getUserFromSession(session);
		} catch (Exception e) {
			return new AJAXMessage(false, AJAXMessage.FailureCode.LoginRequired, e.getMessage());
		}	
		
		//  1. Formularfelder in lokale Variablen speichern 
		String par_abdatum;
		String par_abzeit;
		String par_andatum;
		String par_anzeit;
		String par_von;
		String par_nach;
		String par_plaetze;
		try {
			par_abdatum = params.get("abdatum");
			par_abzeit = params.get("abzeit");
			par_andatum = params.get("andatum");
			par_anzeit = params.get("anzeit");
			par_von = params.get("von");
			par_nach = params.get("nach");
			par_plaetze = params.get("plaetze");
		} catch (Exception e) {
			//Fehler ausgeben, wenn übergebenes Formular unvollständig ist
			return new AJAXMessage(false, AJAXMessage.FailureCode.WarningMessage, "Schwerwiegender Fehler bei der Verarbeitung Ihrer Anfrage.");
		}		

		//  2. 'Dynamische' Liste mit Zwischenhalten abrufen und sortieren
		ArrayList<RouteZeile_Ort> orteListe = new ArrayList<RouteZeile_Ort>();
		try {
			//Am Anfang Abfahrtsort hinzufügen. Id ist immer 0
			orteListe.add(new RouteZeile_Ort(0, par_von));
			int tmpid; //tmpid ist zum Zwischenspeichern der Nummer des Zwischenhalts. Ginge auch ohne tmpid. Ist aber so leichter zum debuggen
			for (Map.Entry<String,String> einParameter : params.entrySet()) {
				if (einParameter.getKey().length() >= 7
					&& einParameter.getKey().substring(0,6).equals("ueber_") //Alle Felder mit den Zwischenorten beginnen mit ueber_
					&& ! einParameter.getKey().equals("ueber_blanko")) { 
					if (!einParameter.getValue().equals("")) {
						tmpid = Integer.parseInt(einParameter.getKey().substring(6));
						orteListe.add(new RouteZeile_Ort(tmpid, einParameter.getValue()));
					}
				}
			}
			java.util.Collections.sort(orteListe);
			//Zum Schluss Zielort hinzufügen. Id ist einfach um 1 höher als die höchste ID der bestehenden Zwischenhalte
			orteListe.add(new RouteZeile_Ort(orteListe.get(orteListe.size()-1).id+1, par_nach));
		} catch (Exception e) {
			return new AJAXMessage(false, AJAXMessage.FailureCode.WarningMessage, "Schwerwiegender Fehler bei der Verarbeitung Ihrer Anfrage.");
		}	
		
		//  3. Eingebewerte umwandeln und prüfen (Datum, Zahl, ...)
		Date abfahrt;
		Date ankunft;
		int iPlaetze;
		
		try {
			abfahrt = this.checkAndConvertDate(par_abdatum , par_abzeit);		
		} catch (Exception e) {
			return new AJAXMessage(false, AJAXMessage.FailureCode.WarningMessage, "Bitte geben Sie ein korrektes Abfahrtsdatum/-uhrzeit ein! (tt.mm.jjjj hh:mm)");
		}
		try {
			ankunft = this.checkAndConvertDate(par_andatum, par_anzeit);		
		} catch (Exception e) {
			return new AJAXMessage(false, AJAXMessage.FailureCode.WarningMessage, "Bitte geben Sie ein korrektes Ankunftsdatum/-uhrzeit ein! (tt.mm.jjjj hh:mm)");
		}
		
		if (par_von.equals("")) {
			return new AJAXMessage(false, AJAXMessage.FailureCode.WarningMessage, "Bitte geben Sie den Abfahrtsort ein!");
		}
		if (par_nach.equals("")) {
			return new AJAXMessage(false, AJAXMessage.FailureCode.WarningMessage, "Bitte geben Sie den Zielort ein!");
		}
		
		try {
			iPlaetze = Integer.parseInt(par_plaetze);
			if (iPlaetze < 1 || iPlaetze > 99) {
				throw new Exception("ungültige Plätzeanzahl");
			}
		} catch (Exception e) {
			return new AJAXMessage(false, AJAXMessage.FailureCode.WarningMessage, "Bitte geben Sie die Anzahl Ihrer freien Plätze ein! (1-99)");
		}
			
			
		/* For Debugging....
		String a = "";
		for (RouteZeile_Ort o : orteListe) {
			a = a + o.id + ": " + o.name;
		}
		return new AJAXMessage(false, AJAXMessage.FailureCode.InfoMessage, a);*/
		
		//Route speichern. ---------------------------------------------------------------
		RouteDAO Rdao = new RouteDAO();
		//RouteDAO Udao = new UserDAO();
		/*in der ArrayList <orteListe> sind Start+Zwischenhalte+Ziel (sortiert) gespeichert.
		 * Diese Liste wird jetzt in ein LinkedHashSet umgewandetl, weil RouteDAO damit 
		 * arbeitet. Die id spielt jetzt keine Rolle mehr. Sie wird beim Speichern der
		 * Route für jeden Routenpunkt neu vergeben.*/
		LinkedHashSet<Routenpunkt> liste = new LinkedHashSet<Routenpunkt>();
		for (RouteZeile_Ort o : orteListe) {
			liste.add(new Routenpunkt(o.name));
		}
		
		try {
			//UserDAO.
			Rdao.newRoute(abfahrt, ankunft, new User("Chef","Koch"), iPlaetze, liste);
		} catch (Exception e) {
			return new AJAXMessage(false, AJAXMessage.FailureCode.WarningMessage, "Schwerwiegender Fehler beim Speichern der neuen Fahrt.");
		}	
		
		return new AJAXMessage(true, AJAXMessage.FailureCode.InfoMessage, "Ihre Fahrt wurde gespeichert.");
		
		
	}
	
	// TODO: Doku
	@RequestMapping(value="/login.json", method=RequestMethod.POST)
	public @ResponseBody AJAXMessage login(String benutzername, String passwort, HttpSession session) {

		// TODO Sinnvoller Code. Jetzt nur Zufallsgenerator zum Testen
		Random randomGenerator = new Random();
		switch (randomGenerator.nextInt(2)) {
			case 0:
				session.setAttribute("userid", benutzername);
				return new AJAXMessage(true, AJAXMessage.FailureCode.None, "");
			default: 
				return new AJAXMessage(false, AJAXMessage.FailureCode.LoginRequired, "Falscher Benutzername oder falsches Passwort.");
		}
	}	
	// TODO: Doku
	@RequestMapping(value="/logout.json", method=RequestMethod.GET)
	public @ResponseBody AJAXMessage logout(HttpSession session) {
		session.invalidate(); 
		return new AJAXMessage(true, AJAXMessage.FailureCode.None, "");
	}
	// TODO: Doku
	@RequestMapping(value="/checkSession.json", method=RequestMethod.GET)
	public @ResponseBody AJAXMessage checkSession(HttpSession session) {
		/*Wenn getUserFromSession keine Exception produziert, dann ist die Sitzung gültig
		 *und die Funktion gibt true zurück. Ansonsten wird false und der Grund zurückgegeben
		 *warum die Session nicht mehr gültig ist (=Fehlermeldung)*/
		try {
			getUserFromSession(session);
		} catch (Exception e) {
			return new AJAXMessage(false, AJAXMessage.FailureCode.None, e.getMessage());
		}
		return new AJAXMessage(true, AJAXMessage.FailureCode.None, "");
	}
	
	
	/**Hilfsfunktion zum Umwandeln eines Strings in ein Date-Objekt
	 * Gültige Datumsformate:
	 * strDatum       strZeit
	 * ------------   -------
	 * - tt.mm.jjjj   hh:mm    
	 * - tt.mm.jj 	  hh:mm
	 * - tt.mm.jjjj
	 * - tt.mm.jj 
	 * Das kleinste, akzeptierte Datum ist der 01.01.2000
	 * 
	 * @param Datum als String
	 * @return Date-Objekt 
	 * @throws Exception: Falls Datum im falschen Format oder ungültig
	 */
	private Date checkAndConvertDate(String strDatum, String strZeit) throws Exception {
		Date tmpDate;
		GregorianCalendar cal = new GregorianCalendar();
		//HowTo String -> Date: http://stackoverflow.com/questions/999172/how-to-parse-date-in-java
		if (strZeit != null && strZeit.length() > 0) 
			tmpDate = new SimpleDateFormat("dd.mm.yyyy hh:mm").parse(strDatum + " " + strZeit);
		else
			tmpDate = new SimpleDateFormat("dd.mm.yyyy").parse(strDatum);
		
		/* 1. String in Datum umwandeln. 
		 * 2. Datum prüfen. Dazu braucht man in Java ein Calendar Objekt. Anders kann man mit einem Datum nicht rechnen
		 * 3. Datum prüfen auf zweistellig (wenn ja, dann + 2000 Jahre)
		 * 4. Datum zwischen 100 und 2000 wird nicht akzeptiert. Ist sicher ein Tippfehler*/
		
		cal.setTime(tmpDate);
		//Falls jemand 12 anstatt von 2012 eintippt, dann muss man 2000 Jahre addieren.
		if (cal.get(Calendar.YEAR) > 0 && cal.get(Calendar.YEAR) < 100)
			cal.add(Calendar.YEAR, 2000);
		if (cal.get(Calendar.YEAR) > 100 && cal.get(Calendar.YEAR) < 2000)
			throw new Exception("Datum ungültig");
		
		return cal.getTime();
	}

	//Hilfsfunktion zum Prüfen ob eine Session gültig ist
	private User getUserFromSession(HttpSession session) throws Exception {
		if (session.getAttribute("userid") == null) {
			throw new Exception(""); //Benutzer ist nicht angemeldet
		}
		
		//Dann prüfen, ob es user gibt
		//throw new Exception("Ihre Zugangsdaten sind nicht mehr gültig.");
		
		//Evtl. ncoh prüfen, ob Session abgelaufen ist
		//throw new Exception("Ihre Sitzung ist abgelaufen. Bitte melden Sie sich erneut an.");
		
		// TODO: Wenn UserDAO fertig ist, dann User aus DB lesen
		return new User("Chef", "Koch");
	}
}
